/* CoordTester.java
 *   CS 3500
 *   Test Program for 'Coord'; Assignment #1
 */

import java.util.Random;

public class CoordTester {

    /** Main method
     *  After compiling it can be run with:
     *    java CoordTester
     *  Or imported into Eclipse
     */
    public static void main(String[] args){
	int totalInstances;
	int totalErrors;

	totalInstances = 100;

	totalErrors = testRandom(totalInstances);
      
	totalErrors += testExceptions();

	/* A few Stats... */
	System.out.println("\nNumber of coordinates tested: " + totalInstances);
	System.out.println("Number of errors found: " + totalErrors);
    }


    // Test 'num' random instances of Coord
    // Returns the number of errors

    public static int testRandom (int num) {
	int count = num;
	int errors = 0;
	while (count > 0) {
	    errors = errors + testSingleRandomCreate();
	    count = count - 1;
	}
    
	// borderline case
	Coord zero = Coord.create(0,0);
	errors = errors + testCreate (zero,0,0);

	return errors;
    }


    // Returns a random integer between 1 and max, inclusive

    public static int randomInt (int max) {
	return new Random().nextInt(max)+1;
    }


    public static int testSingleRandomCreate () {
	int x = randomInt(1000);
	int y = randomInt(1000);
	Coord p = Coord.create(x,y);
	return testCreate(p,x,y);
    }

    public static boolean equalCoords (Coord c1, Coord c2) {
	return (c1.xPos()==c2.xPos() && c1.yPos()==c2.yPos());
    }

    public static int testCreate (Coord p, int x, int y) {
	int errors = 0;
	String front = "Coord.create("+x+","+y+").";

	try{
	    // Coord.create(x,y).xPos() = x
	    if (!(assertT (p.xPos()==x, front+"xPos()"))) errors++;

	    // Coord.create(x,y).yPos() = y
	    if (!(assertT (p.yPos()==y, front+"yPos()"))) errors++;
      
	    // Coord.create(x,y).move(dx,dy) = Coord.create(x+dx,y+dy)
	    int dx, dy;
	    do {
		dx = randomInt(1000)-500;
		dy = randomInt(1000)-500;
	    } while (x+dx < 0 || y+dy < 0);
	    if (!(assertT(equalCoords(p.move(dx,dy),Coord.create(x+dx,y+dy)),
			  front+"move("+dx+","+dy+")"))) errors++;

	    // Coord.create(x,y).add(c) = Coord.create(x+c.xPos(),y+c.yPos())
	    dx = randomInt(1000);
	    dy = randomInt(1000);
	    Coord dp = Coord.create(dx,dy);
	    if (!(assertT(equalCoords(p.add(dp),Coord.create(x+dx,y+dy)),
			  front+"add(Coord.create"+dp.toString()+")"))) errors++;
      
	    // Coord.create(x,y).within(c1,c2) 
	    //        = true   if c1.xPos() <= x <= c2.xPos() and 
	    //                 c1.yPos() <= y <= c2.yPos()
	    //        = false  otherwise
	    int cx = randomInt(1000);
	    int cy = randomInt(1000);
	    Coord c1 = Coord.create(cx,cy);
	    Coord c2 = Coord.create(cx+2,cy+2);
	    boolean expected=false;
	    if (cx <= x && x <= cx+2 && cy <= y && y <= cy+2) expected=true;
	    if (!(assertT(p.within(c1,c2)==expected,
			  front+"within(Coord.create"+c1.toString()+
			  ",Coord.create"+c2.toString()+")")))
		errors++;

	    // Coord.create(x,y).hashCode() = (x+y)*(x+y+1)/2 + y
	    if (!(assertT(p.hashCode()==(x+y)*(x+y+1)/2 + y,
			  front+"hashCode()")))
		errors++;
        
	    // should test equals and hashCode too [ future homework! ]
      
	    if (!(assertT(p.toString().equals("(" + x + "," + y + ")"),
			  front+"toString()"))) errors++;
	    return errors;
	} catch(RuntimeException e) {
      
	    /* If there was an exception anywhere in there, then we
	     *   have a problem */
	    assertT(false, "Exception: "+e.getMessage());
	    return errors+1;
	}
    
    }



    private static int testExceptions () {
	int errors = 0;
	
	// just testing a few coordinates here, we should do more really.
	errors += testCreateException(-1,1);
	errors += testCreateException(1,-1);
	errors += testCreateException(-1,-1);

	errors += testMoveException(1,1,-2,0);
	errors += testMoveException(1,1,0,-2);
	errors += testMoveException(1,1,-2,-2);
	
	return errors;
	
    }
    
    // Create a and ensure that an exception is raised on negative inputs
    private static int testCreateException (int x, int y) {
	if (x >= 0 && y >= 0)
	    return 0;  // sanity check -- make sure that we're trying a wrong input
	try {
	    /*Coord c = */Coord.create(x,y);
	    assertT(false,"Should throw exception in create("+x+","+y+")");
	    return 1;
	} catch (IllegalArgumentException ex) {
	    return 0;
	}
    }

    // Create a coordinate and move it, exception should be raised if the resulting
    // coordinates are negative (see the Specification!)
    private static int testMoveException (int x, int y, int dx, int dy) {
	if (x+dx >= 0 && y+dy >= 0)
	    return 0;  // sanity check -- make sure that we're trying a wrong input
	try {
	    /*Coord c = */Coord.create(x,y).move(dx,dy);
	    assertT(false,"Should throw exception in create("+x+","+y+").move("+dx+","+dy+")");
	    return 1;
	} catch (IllegalArgumentException ex) {
	    return 0;
	}
    }


    /*   Result is expected to be true for passing tests, and false for
     *   failing tests.  If a test fails, we print out the provided
     *   message so the user can see what might have gone wrong. 
     * Be sure to review anything that doesn't make sense. */

    /* returns true if the assertion passed, and false otherwise! */

    private static boolean assertT (boolean result, String msg){
        if(!result){
            System.out.println("\n**ERROR**: "+ msg);
        }
        System.out.print(".");
        return result;
    }
}
